﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "dynamic_impl.h"
#include "../global/head.h"
#include "../xos/head.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    ////////////////////////////////////////////////////////////////////////////////////
    // 

    static dynamic_impl::POOL * pool_ptr = 0;

    ////////////////////////////////////////////////////////////////////////////////////
    //

    dynamic_impl::dynamic_impl()
    {
        m_szFullPath[0] = 0;
        m_szFileName[0] = 0;
        m_hModule = 0;
    }

    dynamic_impl::~dynamic_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int dynamic_impl::get_addr( POOL *** pppPool, LIST *** pppList )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        return ret;
    }

    int dynamic_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int dynamic_impl::term()
    {
        int nRet = 0;

        m_szFullPath[0] = 0;
        m_szFileName[0] = 0;
        free();

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    // 
    // combine load and get_proc_by_name.
    // 
    // 1.try to load : lpszPath/lpszFileName.ext first, if failed, then try : lpszPath/lpszSearchPath/lpszFileName.ext
    // 
    int dynamic_impl::load_and_get( void ** ppv, const char * lpszPath, const char * lpszFileName, const char * lpszProcName, const char * lpszExt, const char * lpszSearchPath )
    {
        void * pRet = 0;
        int ret = 0;

        char szPath[4096] = { 0 };
        xos::i_misc * pMisc = 0;
        xos::i_crt * pCrt = 0;

        if( 0 == ret )
        {
            ret = g_pXos->create( xos::i_xos::XOS_OBJ_MISC, ( void** )&pMisc );
        }

        if( 0 == ret )
        {
            ret = g_pXos->create( xos::i_xos::XOS_OBJ_CRT, ( void** )&pCrt );
        }

        if( 0 == ret )
        {
            if( !lpszPath )
            {
                pMisc->get_process_path( szPath, sizeof( szPath ) / sizeof( szPath ), 0 );
            }
            else
            {
                pCrt->strcpy( szPath, sizeof( szPath ), lpszPath );
            }
        }

        if( 0 == ret )
        {
            if( 0 == ret )
            {
                ret = load( szPath, lpszFileName, lpszExt );
            }
            if( 0 != ret )
            {
                char full_path[4096] = { 0 };
                pCrt->strcpy( full_path, sizeof( full_path ), szPath );
                pMisc->path_append( full_path, lpszSearchPath );
                ret = load( full_path, lpszFileName, lpszExt );
            }
        }

        if( 0 == ret )
        {
            ret = get_proc_by_name( &pRet, lpszProcName );
        }

        if( 0 == ret )
        {
            *ppv = pRet;
        }

        xos_stl::release_interface( pMisc );
        xos_stl::release_interface( pCrt );

        return ret;
    }

    int dynamic_impl::load( const char * lpszFullPath, const char * lpszFile, const char * lpszExt )
    {
        using namespace std;
        int ret = 0;

        char szFile[4096] = { 0 };
        xos::i_misc * pMisc = 0;

        if( 0 == ret )
        {
            ret = g_pXos->create( xos::i_xos::XOS_OBJ_MISC, ( void** )&pMisc );
        }

        ////////////////////////////////////////////////////////////
        // 载入DLL

        if( 0 == ret )
        {
            strcpy( szFile, lpszFullPath );
            strcpy( m_szFileName, lpszFile );
            strcat( m_szFileName, "." );
            strcat( m_szFileName, lpszExt ? lpszExt : "so" );
            pMisc->path_append( szFile, m_szFileName );

            m_hModule = dlopen( szFile, RTLD_LAZY );

            if( !m_hModule )
            {
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            strcpy( m_szFullPath, lpszFullPath );
        }

        xos_stl::release_interface( pMisc );

        return ret;
    }

    int dynamic_impl::get_proc_by_name( void ** ppv, const char * lpszProcName )
    {
        void * pRet = 0;
        int nRet = 0;

        if( 0 == nRet )
        {
            if( !lpszProcName || ( 0 == strlen( lpszProcName ) ) )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            pRet = dlsym( m_hModule, lpszProcName );
            if( !pRet )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            *ppv = pRet;
        }

        return nRet;
    }

    // 
    // get full path and file name
    // 
    const char * dynamic_impl::get_full_path( char * lpszFullPath, int nBufSize )
    {
        int ret = 0;

        xos::i_crt * pCrt = 0;

        if( ( 0 == ret ) && lpszFullPath )
        {
            ret = g_pXos->create( xos::i_xos::XOS_OBJ_CRT, ( void** )&pCrt );
        }

        if( ( 0 == ret ) && lpszFullPath )
        {
            pCrt->strcpy( lpszFullPath, nBufSize, m_szFullPath );
        }

        xos_stl::release_interface( pCrt );

        return m_szFullPath;
    }

    const char * dynamic_impl::get_file_name( char * lpszFileName, int nBufSize )
    {
        int ret = 0;

        xos::i_crt * pCrt = 0;

        if( ( 0 == ret ) && lpszFileName )
        {
            ret = g_pXos->create( xos::i_xos::XOS_OBJ_CRT, ( void** )&pCrt );
        }

        if( ( 0 == ret ) && lpszFileName )
        {
            pCrt->strcpy( lpszFileName, nBufSize, m_szFileName );
        }

        xos_stl::release_interface( pCrt );

        return m_szFileName;
    }

    int dynamic_impl::free()    
    {
        int nRet = 0;

        if( m_hModule )
        {
            dlclose( m_hModule );
            m_hModule = 0;
        }

        return nRet;
    }
} // xos
